package org.idea.ietty.core;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.idea.ietty.common.annotation.RequestMapping;
import org.idea.ietty.common.constants.IettyConstants;
import org.idea.ietty.container.IettyApplicationContext;
import org.idea.ietty.core.factory.ReqHandlerFactory;
import org.idea.ietty.core.handle.ReqHandler;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

import static io.netty.handler.codec.http.HttpUtil.is100ContinueExpected;

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private IettyApplicationContext iettyApplicationContext;

    public HttpRequestHandler(IettyApplicationContext iettyApplicationContext) {
        this.iettyApplicationContext = iettyApplicationContext;
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
        ReqHandler reqHandler = ReqHandlerFactory.buildReqHandler();
        RequestBean requestBean = new RequestBean();
        Map<String, Object> params = new HashMap<>();
        if (req.method().equals(HttpMethod.GET)) {
            params = reqHandler.getParameterHandle(req);
            requestBean.setReqType(HttpMethod.GET.name());
        } else if (req.method().equals(HttpMethod.POST)) {
            params = reqHandler.postParameterHandle(req);
            requestBean.setReqType(HttpMethod.POST.name());
        }
        requestBean.setParamMap(params);
        requestBean.setReqUrl(reqHandler.getReqUrl(req));
        System.out.println(requestBean.toString());

        reqHandlerDispatcher(requestBean,iettyApplicationContext);

        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                Unpooled.copiedBuffer("this is success", CharsetUtil.UTF_8));
//        // 设置头信息
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, IettyConstants.ContentTypeEnum.TEXT_TYPE.getContentTypeDes());
//        // 将html write到客户端
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }


    /**
     * 请求分发器
     *
     * @param requestBean
     * @return
     */
    private Object reqHandlerDispatcher(RequestBean requestBean, IettyApplicationContext iettyApplicationContext) {
        String url = requestBean.getReqUrl();
        String[] reqUrlArr = url.split("/");
        String restControllerMappingUrl = reqUrlArr[1];
        String requestMappingUrl = url.substring(restControllerMappingUrl.length()+1);
        Object restController = iettyApplicationContext.getBean(restControllerMappingUrl);
        Class restControllerClazz = restController.getClass();
        Method[] methods = restControllerClazz.getMethods();
        for (Method method : methods) {
            RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
            if (requestMapping != null && requestMappingUrl.equals(requestMapping.url())) {
                int parameterCount = method.getParameterCount();
                if(parameterCount==0){
                    try {
                        method.invoke(restController);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }else{
                    Map<String,Object> paramMap = requestBean.getParamMap();
                    Object[] objs = new Object[paramMap.size()];
                    int i=0;
                    for (Map.Entry<String,Object> entry : paramMap.entrySet()) {
                        objs[i]=entry.getValue();
                        i++;
                    }
                    try {
                        method.invoke(restController,objs);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }

}